#include "SdkVideo.h"
#include "InSdkDevInfo.h"
#include "InSdkIniBasic.h"
#include "InSdkIniDev.h"

#define DEF_TAG         "Venc"

#define DEF_VIDEO_SIZE_MAX          11
#define DEF_FRAME_DEPTH             2

/* resolation define */
struct resolution_t
{
    unsigned int width;
    unsigned int height;
    unsigned char str[20];
};

/* decoder resolution */
static struct resolution_t g_ChipSdk_Resolutions[DEF_VIDEO_SIZE_MAX] =
{
{640,   360,   "DE_VIDEO_SIZE_360P"},
{640,   480,   "DE_VIDEO_SIZE_VGA"},
{1280,  720,   "DE_VIDEO_SIZE_720P"},
{960,   1080,  "DE_VIDEO_SIZE_960"},
{1920,	1080,  "DE_VIDEO_SIZE_1080P"},
{2304,	1296,  "DE_VIDEO_SIZE_1296P"},
{2560,	1440,  "DE_VIDEO_SIZE_1440P"},
{2560,  1920,  "DE_VIDEO_SIZE_1920P"},
{2688,  1520,  "DE_VIDEO_SIZE_1520P"},
{2880,  1620,  "DE_VIDEO_SIZE_1620P"},
{2880,  2160,  "DE_VIDEO_SIZE_2160P"}
};

int g_SdkVideo_Main_Res = 4;
int g_SdkVideo_Sub_Res = 0;

int g_SdkVideo_MainChnID = VIDEO_CHN0;
int g_SdkVideo_SubChnID = VIDEO_CHN1;

int g_SdkVideo_Handle[2] = {-1, -1};
struct video_stream g_SdkVideo_Stream[2];
struct video_input_frame g_SdkVideo_Frame[2];
struct video_input_frame g_SdkVideo_QRCodeFrame;
static Com_s8 g_SdkVideo_Pic_Flag = DEF_COM_FALSE;
static unsigned char g_SdkVideo_Start_Venc;

int SdkVideo_VencInit(int dev_id)
{
    int ret = -1;
    /* open venc */
    struct venc_param ve_param;
    struct venc_rc_param rc_param;

    memset(&ve_param,0,sizeof(ve_param));
    memset(&rc_param,0,sizeof(rc_param));

    rc_param.enable_MMA = 1;

    if (dev_id == VIDEO_CHN0)
    {
        ve_param.width  = g_ChipSdk_Resolutions[g_SdkVideo_Main_Res].width;
        ve_param.height = g_ChipSdk_Resolutions[g_SdkVideo_Main_Res].height;
        ve_param.target_kbps = 1024;            //resolution width
        ve_param.max_kbps = 1024;           //resolution height
        ve_param.minqp       = 28;          //qp set
        ve_param.maxqp       = 43;          //qp max value
    }
    else
    {
        ve_param.width  = g_ChipSdk_Resolutions[g_SdkVideo_Sub_Res].width;
        ve_param.height = g_ChipSdk_Resolutions[g_SdkVideo_Sub_Res].height;
        ve_param.target_kbps = 512;            //resolution width
        ve_param.max_kbps = 512;           //resolution height
        ve_param.minqp       = 28;          //qp set
        ve_param.maxqp       = 43;          //qp max value
    }

#if CMAKE_PRODUCT_TEST
    ve_param.target_kbps = 256;
    ve_param.max_kbps = 256;
#endif

    ve_param.fps    = DEF_SDK_VIDEO_FPS;               //fps set
    ve_param.goplen = 3 * DEF_SDK_VIDEO_FPS;               //gop set
    ve_param.br_mode     = BR_MODE_CBR; //br mode
    ve_param.initqp       = 90;//(ve_param.minqp + ve_param.maxqp)/2;    //qp value
    ve_param.jpeg_qlevel = JPEG_QLEVEL_DEFAULT;     //jpeg qlevel
    ve_param.chroma_mode = CHROMA_4_2_0;            //chroma mode
    ve_param.max_picture_size = 0;                  //0 means default
    ve_param.enc_level        = 30;                 //enc level
    ve_param.smart_mode       = SMART_DISABLE;                  //smart mode set
    ve_param.smart_goplen     = 100;                //smart mode value
    ve_param.smart_quality    = 50;                 //quality
    ve_param.smart_static_value = 0;                //value
    ve_param.enc_out_type   = HEVC_ENC_TYPE;           //enc type
    ve_param.profile        = PROFILE_HEVC_MAIN;

    ret = ak_venc_open_ex(&ve_param, &rc_param,  &g_SdkVideo_Handle[dev_id]);
    if (ret || (-1 == g_SdkVideo_Handle[dev_id]))
    {
        ak_print_error_ex(MODULE_ID_APP, "dev%d open venc failed\n", dev_id);
        return ret;
    }
    ak_venc_strictlylimit_frameSize(g_SdkVideo_Handle[dev_id],400);

    return 0;
}

int Ext_SdkVideo_Init(void)
{
    g_SdkVideo_Start_Venc = DEF_COM_FALSE;

    if(Ext_InComFile_Access(DEF_SENSOR_INFO_QXGA) == DEF_COM_FILE_EXIST)
    {
        g_SdkVideo_Main_Res = 5;
    }

    /*
     * step 0: global value initialize
     */
    int ret = -1;                                //return value
    int mainwidth = g_ChipSdk_Resolutions[g_SdkVideo_Main_Res].width;
    int mainheight = g_ChipSdk_Resolutions[g_SdkVideo_Main_Res].height;
    int subwidth = g_ChipSdk_Resolutions[g_SdkVideo_Sub_Res].width;
    int subheight = g_ChipSdk_Resolutions[g_SdkVideo_Sub_Res].height;
    VI_CHN_ATTR chn_attr;
    VI_CHN_ATTR chn_attr_sub;
    char video_cfg[DEF_COM_EXPORT_LEN];
    char cfg_bak[DEF_COM_EXPORT_LEN];

    /* open vi flow */
    /*
     * step 1: open video input device
     */
    ret = ak_vi_open(VIDEO_DEV0);
    if (AK_SUCCESS != ret)
    {
        printf("vi device %d open failed\n", VIDEO_DEV0);
        return ret;
    }

    memset(cfg_bak,0,sizeof(cfg_bak));
    memset(video_cfg,0,sizeof(video_cfg));
    Ext_InSdkGetInfo_export(DEF_EXPORT_SENSOR_CONF,video_cfg);
    sprintf(cfg_bak,"/mnt/config/%s",video_cfg + 11);
    if(Ext_InComFile_Access(cfg_bak) == DEF_COM_FILE_EXIST)
    {
        memset(video_cfg,0,sizeof(video_cfg));
        memcpy(video_cfg,cfg_bak,sizeof(cfg_bak));
    }

    /*
     * step 2: load isp config
     */
    ret = ak_vi_load_sensor_cfg(VIDEO_DEV0, video_cfg);
    if (AK_SUCCESS != ret)
    {
        PRT_ERR(DEF_TAG,"vi device %d load isp cfg [%s] failed!\n", VIDEO_DEV0, video_cfg);
        return ret;
    }
    PRT_INFO(DEF_TAG,"video config: %s\n",video_cfg);

    int v_crop_x = 0;
    int v_crop_y = 0;

    /*
     * step 3: get sensor support max resolution
     */
    VI_DEV_ATTR dev_attr;
    memset(&dev_attr, 0, sizeof(VI_DEV_ATTR));
    dev_attr.dev_id = VIDEO_DEV0;
    dev_attr.crop.left = v_crop_x;
    dev_attr.crop.top = v_crop_y;
    dev_attr.crop.width = (mainwidth - v_crop_x * 2);
    dev_attr.crop.height = (mainheight - v_crop_y);

    if(Ext_InComFile_Access(DEF_SENSOR_INFO_QXGA) == DEF_COM_FILE_EXIST)
    {
        dev_attr.max_width = mainwidth;
        dev_attr.max_height = mainheight;
    }
    else
    {
        dev_attr.max_width = DEF_SENSOR_1080P_WIDTH;
        dev_attr.max_height = DEF_SENSOR_1080P_HEIGHT;
    }

    dev_attr.sub_max_width = SENSOR_SUB_WIDTH;
    dev_attr.sub_max_height = SENSOR_SUB_HEIGHT;

    RECTANGLE_S res;                //max sensor resolution
    /* get sensor resolution */
    ret = ak_vi_get_sensor_resolution(VIDEO_DEV0, &res);
    if (ret)
    {
        PRT_ERR(DEF_TAG,"Can't get dev[%d]resolution\n", VIDEO_DEV0);
        ak_vi_close(VIDEO_DEV0);
        return ret;
    }
    else
    {
        PRT_DBG(DEF_TAG,"get dev res w:[%d]h:[%d]\n",res.width, res.height);
        dev_attr.crop.width = res.width;
        dev_attr.crop.height = res.height;
    }

    /*
     * step 4: set vi device working parameters
     * default parameters: 25fps, day mode
     */
    ret = ak_vi_set_dev_attr(VIDEO_DEV0, &dev_attr);
    if (ret)
    {
        printf("vi device %d set device attribute failed!\n", VIDEO_DEV0);
        ak_vi_close(VIDEO_DEV0);
        return ret;
    }

#if CMAKE_COM_PROCESS
    g_SdkVideo_Main_Res = 2;
#endif

    /*
     * step 5: set main channel attribute
     */
    memset(&chn_attr, 0, sizeof(VI_CHN_ATTR));
    chn_attr.chn_id = g_SdkVideo_MainChnID;
    chn_attr.res.width = mainwidth;
    chn_attr.res.height = mainheight;
    chn_attr.frame_depth = DEF_FRAME_DEPTH;
    /*disable frame control*/
    chn_attr.frame_rate = DEF_SDK_VIDEO_FPS;
    ret = ak_vi_set_chn_attr(g_SdkVideo_MainChnID, &chn_attr);
    if (ret) {
        printf("vi device %d set channel [%d] attribute failed!\n", VIDEO_DEV0, g_SdkVideo_MainChnID);
        ak_vi_close(VIDEO_DEV0);
        return ret;
    }
    printf("vi device %d main sub channel attribute\n", VIDEO_DEV0);

    /*
     * step 6: set sub channel attribute
     */
    memset(&chn_attr_sub, 0, sizeof(VI_CHN_ATTR));
    chn_attr_sub.chn_id = g_SdkVideo_SubChnID;
    chn_attr_sub.res.width = subwidth;
    chn_attr_sub.res.height = subheight;
    chn_attr_sub.frame_depth = DEF_FRAME_DEPTH;
    /*disable frame control*/
    chn_attr_sub.frame_rate = DEF_SDK_VIDEO_FPS;
    ret = ak_vi_set_chn_attr(g_SdkVideo_SubChnID, &chn_attr_sub);
    if (ret)
    {
        printf("vi device %d set channel [%d] attribute failed!\n", VIDEO_DEV0, g_SdkVideo_SubChnID);
        ak_vi_close(VIDEO_DEV0);
        return ret;
    }
    printf("vi device %d set sub channel attribute\n", VIDEO_DEV0);

    /*
     * step 8: enable vi device
     */
    ret = ak_vi_enable_dev(VIDEO_DEV0);
    if (ret)
    {
        printf( "vi device %d enable device  failed!\n", VIDEO_DEV0);
        ak_vi_close(VIDEO_DEV0);
        return ret;
    }

    /*
     * step 9: enable vi main channel
     */
    ret = ak_vi_enable_chn(g_SdkVideo_MainChnID);
    if(ret)
    {
        printf( "vi channel[%d] enable failed!\n", g_SdkVideo_MainChnID);
        ak_vi_close(VIDEO_DEV0);
        return ret;
    }

    /*
     * step 10: enable vi sub channel
     */
    ret = ak_vi_enable_chn(g_SdkVideo_SubChnID);
    if(ret)
    {
        ak_print_error_ex(MODULE_ID_APP, "vi channel[%d] enable failed!\n",g_SdkVideo_SubChnID);
        ak_vi_close(VIDEO_DEV0);
        return ret;
    }

    SdkVideo_VencInit(g_SdkVideo_MainChnID);
    SdkVideo_VencInit(g_SdkVideo_SubChnID);

    UnInSdkIniCfgKeyData udata;
    memset(&udata,0,sizeof(udata));
    Ext_InSdkIniIot_GetData(INI_DEV_INT_ANTI_FLICKER,&udata);
    Ext_SdkVideo_SetAntiFlicker(udata.val);
    ret = Ext_InSdkIniBasic_GetVal(INI_BASIC_VIDEO_FLIP);
    if(ret)
    {
        ak_vpss_effect_set(VIDEO_DEV0,VPSS_FLIP_MIRROR,3);
    }
    else
    {
        ak_vpss_effect_set(VIDEO_DEV0,VPSS_FLIP_MIRROR,0);
    }

    Ext_SdkOsd_Init();
    Ext_SdkNightMonitor_Init();
    if(Ext_InComFile_Access(DEF_FLAG_OPEN_ISPTOOL) == DEF_COM_FILE_EXIST)
    {
        ak_its_start(8765);
    }

    return 0;
}

void Ext_SdkVideo_Start(void)
{
    g_SdkVideo_Start_Venc = DEF_COM_TRUE;
}

int Ext_SdkVideo_Exit(void)
{
    if(Ext_InComFile_Access(DEF_FLAG_OPEN_ISPTOOL) == DEF_COM_FILE_EXIST)
    {
        ak_its_stop();
    }

    /* release osd */
    ak_osd_ex_destroy();

    ak_venc_close(g_SdkVideo_Handle[g_SdkVideo_MainChnID]);
    ak_venc_close(g_SdkVideo_Handle[g_SdkVideo_SubChnID]);
    ak_vi_disable_chn(g_SdkVideo_MainChnID);
    ak_vi_disable_chn(g_SdkVideo_SubChnID);
    ak_vi_disable_dev(VIDEO_DEV0);
    ak_vi_close(VIDEO_DEV0);

    ak_print_normal(MODULE_ID_VENC,"video encode demo exit ...\n");

    return 0;
}

int Ext_SdkMediaCom_GetVideoData(int chn,pStSdkVideoInfo info)
{
    int ret;

    if((chn == g_SdkVideo_SubChnID) && (g_SdkVideo_Pic_Flag == DEF_COM_TRUE))
    {
        usleep(10);
        return DEF_COM_FAILED;
    }

    memset(&g_SdkVideo_Frame[chn], 0, sizeof(g_SdkVideo_Frame[chn]));
    ret = ak_vi_get_frame(chn, &g_SdkVideo_Frame[chn]);
    if (ret != 0)
    {
        usleep(10 * 1000);
        return DEF_COM_FAILED;
    }

    memset(&g_SdkVideo_Stream[chn],0,sizeof(g_SdkVideo_Stream[chn]));
    ret = ak_venc_encode_frame(g_SdkVideo_Handle[chn],
                               g_SdkVideo_Frame[chn].vi_frame.data,
                               g_SdkVideo_Frame[chn].vi_frame.len,
                               g_SdkVideo_Frame[chn].mdinfo,
                               &g_SdkVideo_Stream[chn]);
    if(ret)
    {
        /* send to encode failed */
        printf("send to encode failed\n");
        ak_vi_release_frame(chn, &g_SdkVideo_Frame[chn]);
        return DEF_COM_FAILED;
    }
    else
    {
        if(g_SdkVideo_Stream[chn].len > 0)
        {
            info->buf = g_SdkVideo_Stream[chn].data;
            info->size = g_SdkVideo_Stream[chn].len;
            info->type = (g_SdkVideo_Stream[chn].frame_type == FRAME_TYPE_I) ? SDK_FRAME_TYPE_I : SDK_FRAME_TYPE_P;
            info->pts = g_SdkVideo_Frame[chn].vi_frame.ts;
        }
        else
        {
            printf("encode err, maybe drop\n");
            Ext_SdkMediaCom_ReleaseVideoData(chn);
            return DEF_COM_FAILED;
        }
    }

    return DEF_COM_SUCCESS;
}

void Ext_SdkMediaCom_ReleaseVideoData(int chn)
{
    ak_venc_release_stream(g_SdkVideo_Handle[chn],&g_SdkVideo_Stream[chn]);
    ak_vi_release_frame(chn,&g_SdkVideo_Frame[chn]);
}

int Ext_SdkMediaCom_GetQRCodeData(pStSdkQrcodeInfo info)
{
    int ret;

    memset(&g_SdkVideo_QRCodeFrame, 0, sizeof(g_SdkVideo_QRCodeFrame));
    ret = ak_vi_get_frame(g_SdkVideo_SubChnID, &g_SdkVideo_QRCodeFrame);
    if (ret != 0)
    {
        usleep(10 * 1000);
        return DEF_COM_FAILED;
    }

    info->buf = g_SdkVideo_QRCodeFrame.vi_frame.data;

    return DEF_COM_SUCCESS;
}

void Ext_SdkMediaCom_ReleaseQRCodeData(void)
{
    ak_vi_release_frame(g_SdkVideo_SubChnID,&g_SdkVideo_QRCodeFrame);
}

void Ext_SdkMediaCom_RequestIDR(void)
{
    PRT_INFO(DEF_TAG,"set I frame\n");

    ak_venc_request_idr(g_SdkVideo_Handle[g_SdkVideo_MainChnID]);
    ak_venc_request_idr(g_SdkVideo_Handle[g_SdkVideo_SubChnID]);
}

void Ext_SdkMediaCom_SavePic(void)
{
    int ret = -1;
    static int handle_id = -1;
    static char init_flag = 0;
    char snap_path[64];
    FILE *save_fp = NULL;
    struct video_stream stream;
    struct video_input_frame frame;
    int jpeg_chn = g_SdkVideo_SubChnID;

    if(init_flag == 0)
    {
        struct venc_param ve_param;

        memset(&ve_param,0,sizeof(ve_param));

        ve_param.width  = g_ChipSdk_Resolutions[g_SdkVideo_Sub_Res].width;            //resolution width
        ve_param.height = g_ChipSdk_Resolutions[g_SdkVideo_Sub_Res].height;           //resolution height
        ve_param.fps    = DEF_SDK_VIDEO_FPS;               //fps set
        ve_param.goplen = 2 * DEF_SDK_VIDEO_FPS;               //gop set
        ve_param.target_kbps = 1024;         //k bps
        ve_param.max_kbps    = 1024;        //max kbps
        ve_param.br_mode     = BR_MODE_CBR; //br mode
        ve_param.minqp       = 28;          //qp set
        ve_param.maxqp       = 43;          //qp max value
        ve_param.initqp      = (ve_param.minqp + ve_param.maxqp)/2;    //qp value
        ve_param.jpeg_qlevel = JPEG_QLEVEL_HIGHEST;     //jpeg qlevel
        ve_param.chroma_mode = CHROMA_4_2_0;            //chroma mode
        ve_param.max_picture_size = 0;                  //0 means default
        ve_param.enc_level        = 30;                 //enc level
        ve_param.smart_mode       = 0;                  //smart mode set
        ve_param.smart_goplen     = 100;                //smart mode value
        ve_param.smart_quality    = 50;                 //quality
        ve_param.smart_static_value = 0;                //value
        ve_param.enc_out_type = MJPEG_ENC_TYPE;           //enc type
        ve_param.profile     = PROFILE_JPEG;

        ret = ak_venc_open(&ve_param,&handle_id);
        if (ret || (-1 == handle_id))
        {
            ak_print_error_ex(MODULE_ID_APP, "dev0 open venc failed\n");
            return;
        }
        init_flag = 1;
    }

    memset(snap_path,0,sizeof(snap_path));
    sprintf(snap_path,"%s/%s",DEF_COM_SAVE_JEP_PATH,DEF_COM_JPEG_NAME);
    save_fp = fopen(snap_path,"w");
    if(save_fp == NULL)
    {
        ak_print_error_ex(MODULE_ID_APP, "fopen failed, errno = %d\n", errno);
        return;
    }

    g_SdkVideo_Pic_Flag = DEF_COM_TRUE;

    while (g_ComThread_Running)
    {
        memset(&frame, 0, sizeof(frame));
        ret = ak_vi_get_frame(jpeg_chn, &frame);
        if (!ret)
        {
            memset(&stream, 0, sizeof(stream));
            /* send it to encode */
            ret = ak_venc_encode_frame(handle_id, frame.vi_frame.data, frame.vi_frame.len, frame.mdinfo, &stream);
            if (ret)
            {
                /* send to encode failed */
                ak_print_error_ex(MODULE_ID_APP, "send to encode failed\n");
            }
            else
            {
                if (stream.len > 0)
                {
                    if (fwrite(stream.data, stream.len, 1, save_fp) <= 0)
                    {
                        ak_print_error_ex(MODULE_ID_VENC, "fwrite failed \n");
                    }
                }
                else
                {
                    ak_print_notice_ex(MODULE_ID_VENC, "encode err, maybe drop\n");
                }
                ak_venc_release_stream(handle_id, &stream);
            }
            ak_vi_release_frame(jpeg_chn, &frame);
            break;
        }
        else
        {
            usleep(50 * 1000);
            continue;
        }
    }

    if (NULL != save_fp)
    {
        fclose(save_fp);
        save_fp = NULL;
    }

    g_SdkVideo_Pic_Flag = DEF_COM_FALSE;
    PRT_NORMAL("save jpeg end\n");
}

int Ext_SdkMediaCom_SetFlip(int mode)
{
    Com_s32 ret;
    Com_s32 val;

    ret = Ext_InSdkIniBasic_GetVal(INI_BASIC_VIDEO_FLIP);
    if(ret)
    {
        val = (mode == 1) ? 0 : 3;
    }
    else
    {
        val = (mode == 1) ? 3 : 0;
    }

    ret =  ak_vpss_effect_set(VIDEO_DEV0,VPSS_FLIP_MIRROR,val);
    if(ret != 0)
    {
        printf("ak_vpss_effect_set error\n");
        return -1;
    }
    return mode;
}

void Ext_SdkMediaCom_SetVpssEffect(EnSdkVideoEffect effect,int val)
{
    Com_s32 ret = 0;

    printf("effect: %d,val: %d\n",effect,val);

    switch(effect)
    {
    case VIDEO_EFFECT_BRIGHTNESS :
    {
        int s_val = val - 50;
        ret =  ak_vpss_effect_set(VIDEO_DEV0,VPSS_EFFECT_BRIGHTNESS,s_val);
        if(ret != 0)
        {
            printf("effect set brightness error\n");
            return;
        }
    }
        break;

    case VIDEO_EFFECT_CONTRAST :
    {
        int s_val = val - 50;
        ret =  ak_vpss_effect_set(VIDEO_DEV0,VPSS_EFFECT_CONTRAST,s_val);
        if(ret != 0)
        {
            printf("effect set contrast error\n");
            return;
        }
    }
        break;

    default :
        printf("no this type\n");
        break;
    }
}

void Ext_SdkVideo_SetAntiFlicker(enum Vpss_anti_flicker effect)
{
    PRT_NORMAL("set_anti_flicker effect: %d\n",effect);

    switch(effect)
    {
    case VPSS_POWER_HZ_50 :
    {
        ak_vpss_effect_set(VIDEO_DEV0,VPSS_POWER_HZ,50);
    }
        break;

    case VPSS_POWER_HZ_60 :
    {
        ak_vpss_effect_set(VIDEO_DEV0,VPSS_POWER_HZ,60);
    }
        break;

    case VPSS_POWER_HZ_CLOSE :
    {

    }
        break;

    default :
        printf("no this type\n");
        break;
    }
    ak_vpss_set_force_anti_flicker_flag_ex(VIDEO_DEV0,AK_FALSE,64);
}
